﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfWordsLearner.Model;

namespace WpfWordsLearner
{
	public enum ImportSource
	{
		File = 0,
		XML = 1
	}

	public sealed class ImportManager
	{
		private string m_sourceFile = string.Empty;
		private string m_destFile = string.Empty;
		private ImportSource m_type;

		TaskScheduler m_scheduler = TaskScheduler.FromCurrentSynchronizationContext();

		public ImportManager(string from, string to)
		{
			if (string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to))
				throw new ArgumentException("Parameters cannot be null or empty");

			m_destFile = to;
			m_sourceFile = from;
		}

		public ImportManager(string from, ImportSource source)
		{
			if (string.IsNullOrEmpty(from))
				throw new ArgumentException("Parameters cannot be null or empty");

			m_sourceFile = from;
			m_type = source;
		}

		public event EventHandler Completed;
		private void OnCompleted(Task task)
		{
			EventHandler handler = Completed;
			if (handler != null)
			{
				handler(this, new EventArgs());
			}
			task.Dispose();
		}

		public event EventHandler Changed;
		private void OnChanged()
		{
			EventHandler handler = Changed;
			if (handler != null)
			{
				handler(this, new EventArgs());
			}
		}

		private void ImportWork()
		{
			WeakReference existed = new WeakReference(WordsManager.Instance.GetWordsList());

			List<WordsModel> imported = null;

			switch (m_type)
			{
				case ImportSource.XML:
					imported = WordsManager.GetWordsList(m_sourceFile);
					break;

				case ImportSource.File:
					imported = WordsManager.Instance.GetWordsListFromFile(m_sourceFile);
					break;

				default:
					break;
			}
			StringBuilder sb = new StringBuilder();

			foreach (WordsModel model in imported)
			{
				var word = (existed.Target as List<WordsModel>).FirstOrDefault(x => string.Compare(x.EnglishWord.Trim(), model.EnglishWord.Trim(), true) == 0);
				if (word == null)
				{
					(existed.Target as List<WordsModel>).Add(model);
					Task.Factory.StartNew(() => OnChanged(), System.Threading.CancellationToken.None, TaskCreationOptions.None, m_scheduler).Wait();
					System.Threading.Thread.Sleep(18);
				}
				else
				{
					string[] exTrans = word.Translate.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
					string[] newTrans = model.Translate.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
					foreach (string newWord in newTrans)
					{
						if (exTrans.Contains(newWord.Trim()))
							continue;
						else
						{
							sb.AppendFormat("{0},", newWord);
						}
					}
					if (sb.Length > 1)
					{
						sb.Append(word.Translate);
					}
					word.Translate = sb.ToString();
					sb.Clear();

					Task.Factory.StartNew(() => OnChanged(), System.Threading.CancellationToken.None, TaskCreationOptions.None, m_scheduler).Wait();
					System.Threading.Thread.Sleep(18);
				}
			}
			sb = null;

			WordsManager.Instance.Import((existed.Target as List<WordsModel>));
			Task.Factory.StartNew(() => OnChanged(), System.Threading.CancellationToken.None, TaskCreationOptions.None, m_scheduler).Wait();
		}

		private void ImportWork(string fileToSave)
		{
			List<WordsModel> imported = null;

			switch (m_type)
			{
				case ImportSource.XML:
					imported = WordsManager.GetWordsList(m_sourceFile);
					break;

				case ImportSource.File:
					imported = WordsManager.Instance.GetWordsListFromFile(m_sourceFile);
					break;

				default:
					break;
			}

			System.Xml.Linq.XDocument doc = new System.Xml.Linq.XDocument(
											new System.Xml.Linq.XDeclaration("1.0", "UTF-8", "yes"),
											new System.Xml.Linq.XElement("Words")
											);

			foreach (WordsModel model in imported)
			{
				doc.Root.Add(new System.Xml.Linq.XElement("Word",
											new System.Xml.Linq.XElement("English", EncryptionManager.Encrypt(model.EnglishWord)),
											new System.Xml.Linq.XElement("Translate", EncryptionManager.Encrypt(model.Translate)),
											new System.Xml.Linq.XElement("Complicated", model.IsComplicated)
											));

				Task.Factory.StartNew(() => OnChanged(), System.Threading.CancellationToken.None, TaskCreationOptions.None, m_scheduler).Wait();
				System.Threading.Thread.Sleep(12);
			}

			doc.Save(fileToSave);
		}

		public void Run()
		{
			Task.Factory.StartNew(ImportWork, TaskCreationOptions.LongRunning).ContinueWith((Task t) => { OnCompleted(t); t.Dispose(); });
		}

		public void Run(string destFile)
		{
			Task.Factory.StartNew((file) => ImportWork(destFile), TaskCreationOptions.LongRunning).ContinueWith((Task t) => { OnCompleted(t); t.Dispose(); });
		}
	}

	public sealed class ExportManager
	{
		private string m_destFile = string.Empty;

		TaskScheduler m_scheduler = TaskScheduler.FromCurrentSynchronizationContext();

		public ExportManager(string from)
		{
			if (string.IsNullOrEmpty(from))
				throw new ArgumentException("Parameters cannot be null or empty");

			m_destFile = from;
		}

		public event EventHandler Completed;
		private void OnCompleted(Task task)
		{
			EventHandler handler = Completed;
			if (handler != null)
			{
				handler(this, new EventArgs());
			}
		}

		public event EventHandler Changed;
		private void OnChanged()
		{
			if (Changed != null)
			{
				Changed(this, new EventArgs());
			}
		}

		private void ExportWork()
		{
			var existed = WordsManager.Instance.GetWordsList();

			using (System.IO.StreamWriter sw = new System.IO.StreamWriter(m_destFile))
			{
				foreach (WordsModel model in existed)
				{
					sw.WriteLine(string.Format("{0} - {1}", model.EnglishWord, model.Translate));
					System.Threading.Thread.Sleep(10);
					Task.Factory.StartNew(() => OnChanged(), System.Threading.CancellationToken.None, TaskCreationOptions.None, m_scheduler).Wait();
				}
				sw.Flush();
			}
		}

		public void RunExport()
		{
			var task = Task.Factory.StartNew(ExportWork, TaskCreationOptions.LongRunning).ContinueWith((Task t) => OnCompleted(t));
		}
	}
}